package com.xhj.mybatis.reflection;

import java.util.Arrays;

/**
 * ArrayUtil
 *
 * @author XJks
 * @description 提供可以处理数组的 hashCode、equals 和 toString 方法。
 */
public class ArrayUtil {

    /**
     * 返回指定对象的 hashCode 值。
     *
     * @param obj 要获取 hashCode 的对象，可以是数组或 null。
     * @return obj 的 hashCode，如果 obj 为 null 则返回 0
     */
    public static int hashCode(Object obj) {
        if (obj == null) {
            // 如果对象为 null，返回 0，和 Arrays.hashCode()、Objects.hashCode() 保持一致
            return 0;
        }
        // 获取对象的类类型
        final Class<?> clazz = obj.getClass();
        if (!clazz.isArray()) {
            // 如果不是数组，直接返回对象的 hashCode
            return obj.hashCode();
        }
        // 获取数组的元素类型
        final Class<?> componentType = clazz.getComponentType();
        if (long.class.equals(componentType)) {
            // 如果是 long 类型数组，调用 Arrays.hashCode(long[])
            return Arrays.hashCode((long[]) obj);
        } else if (int.class.equals(componentType)) {
            // 如果是 int 类型数组
            return Arrays.hashCode((int[]) obj);
        } else if (short.class.equals(componentType)) {
            // 如果是 short 类型数组
            return Arrays.hashCode((short[]) obj);
        } else if (char.class.equals(componentType)) {
            // 如果是 char 类型数组
            return Arrays.hashCode((char[]) obj);
        } else if (byte.class.equals(componentType)) {
            // 如果是 byte 类型数组
            return Arrays.hashCode((byte[]) obj);
        } else if (boolean.class.equals(componentType)) {
            // 如果是 boolean 类型数组
            return Arrays.hashCode((boolean[]) obj);
        } else if (float.class.equals(componentType)) {
            // 如果是 float 类型数组
            return Arrays.hashCode((float[]) obj);
        } else if (double.class.equals(componentType)) {
            // 如果是 double 类型数组
            return Arrays.hashCode((double[]) obj);
        } else {
            // 如果是对象数组
            return Arrays.hashCode((Object[]) obj);
        }
    }

    /**
     * 比较两个对象是否相等。
     * <ul>
     * <li>如果两个对象都为 null，返回 true</li>
     * <li>如果两个对象类型相同且 equals 返回 true，返回 true</li>
     * <li>如果两个对象都是数组且元素类型相同，使用 Arrays.equals 比较</li>
     * </ul>
     *
     * @param thisObj 左侧对象，可以是数组或 null
     * @param thatObj 右侧对象，可以是数组或 null
     * @return 如果两个对象相等返回 true，否则返回 false
     */
    public static boolean equals(Object thisObj, Object thatObj) {
        if (thisObj == null) {
            // 如果左侧对象为 null，只有右侧也为 null 才相等
            return thatObj == null;
        } else if (thatObj == null) {
            // 如果右侧对象为 null，左侧不为 null，则不相等
            return false;
        }
        // 获取左侧对象的类类型
        final Class<?> clazz = thisObj.getClass();
        if (!clazz.equals(thatObj.getClass())) {
            // 如果两个对象类型不同，直接返回不相等
            return false;
        }
        if (!clazz.isArray()) {
            // 如果不是数组，直接用 equals 方法比较
            return thisObj.equals(thatObj);
        }
        // 获取数组元素类型
        final Class<?> componentType = clazz.getComponentType();
        if (long.class.equals(componentType)) {
            // long 类型数组比较
            return Arrays.equals((long[]) thisObj, (long[]) thatObj);
        } else if (int.class.equals(componentType)) {
            // int 类型数组比较
            return Arrays.equals((int[]) thisObj, (int[]) thatObj);
        } else if (short.class.equals(componentType)) {
            // short 类型数组比较
            return Arrays.equals((short[]) thisObj, (short[]) thatObj);
        } else if (char.class.equals(componentType)) {
            // char 类型数组比较
            return Arrays.equals((char[]) thisObj, (char[]) thatObj);
        } else if (byte.class.equals(componentType)) {
            // byte 类型数组比较
            return Arrays.equals((byte[]) thisObj, (byte[]) thatObj);
        } else if (boolean.class.equals(componentType)) {
            // boolean 类型数组比较
            return Arrays.equals((boolean[]) thisObj, (boolean[]) thatObj);
        } else if (float.class.equals(componentType)) {
            // float 类型数组比较
            return Arrays.equals((float[]) thisObj, (float[]) thatObj);
        } else if (double.class.equals(componentType)) {
            // double 类型数组比较
            return Arrays.equals((double[]) thisObj, (double[]) thatObj);
        } else {
            // 对象数组比较
            return Arrays.equals((Object[]) thisObj, (Object[]) thatObj);
        }
    }

    /**
     * 如果 obj 是数组，调用 Arrays 的 toString 方法，否则调用 Object 的 toString 方法。
     * 如果 obj 为 null，返回 "null" 字符串。
     *
     * @param obj 需要转换为字符串的对象，可以是数组或 null。
     * @return obj 的字符串表示形式
     */
    public static String toString(Object obj) {
        if (obj == null) {
            // 如果对象为 null，返回 "null"
            return "null";
        }
        // 获取对象的类类型
        final Class<?> clazz = obj.getClass();
        if (!clazz.isArray()) {
            // 如果不是数组，直接调用 toString 方法
            return obj.toString();
        }
        // 获取数组元素类型
        final Class<?> componentType = obj.getClass().getComponentType();
        if (long.class.equals(componentType)) {
            // long 类型数组转字符串
            return Arrays.toString((long[]) obj);
        } else if (int.class.equals(componentType)) {
            // int 类型数组转字符串
            return Arrays.toString((int[]) obj);
        } else if (short.class.equals(componentType)) {
            // short 类型数组转字符串
            return Arrays.toString((short[]) obj);
        } else if (char.class.equals(componentType)) {
            // char 类型数组转字符串
            return Arrays.toString((char[]) obj);
        } else if (byte.class.equals(componentType)) {
            // byte 类型数组转字符串
            return Arrays.toString((byte[]) obj);
        } else if (boolean.class.equals(componentType)) {
            // boolean 类型数组转字符串
            return Arrays.toString((boolean[]) obj);
        } else if (float.class.equals(componentType)) {
            // float 类型数组转字符串
            return Arrays.toString((float[]) obj);
        } else if (double.class.equals(componentType)) {
            // double 类型数组转字符串
            return Arrays.toString((double[]) obj);
        } else {
            // 对象数组转字符串
            return Arrays.toString((Object[]) obj);
        }
    }
}
